using Magiq.Databases;
using Magiq.Tests.Support;
using NUnit.Framework;

namespace Magiq.Tests
{
    [TestFixture]
    public class SelectStatementParserTests
    {
        private readonly SelectStatementParser parser = new SelectStatementParser();
   
        [Test]
        public void ShouldSplitCommaDelimitedValues()
        {
            var select = parser.Parse("SELECT bla,ble,bli FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldParseStatementWithoutWhere()
        {
            var select = parser.Parse("SELECT bla,ble,bli");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.Empty);
        }

        [Test]
        public void ShouldNotRemoveFromWordUsedAsValueExpression()
        {
            var select = parser.Parse("SELECT bla + 'FROM',[FROM],(bli AS FROM) FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla + 'FROM'"));
            select[1].Should(Be.EqualTo("[FROM]"));
            select[2].Should(Be.EqualTo("(bli AS FROM)"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldRemoveNewLines()
        {
            var select = parser.Parse("SELECT bla,ble,bli\r\nFROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldAcceptUnicodeNPrefix()
        {
            var select = parser.Parse("SELECT bla + N'lala' AS Bla FROM xxxxx");
            select.Should(Have.Length(1));
            select[0].Should(Be.EqualTo("bla + N'lala'"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldAcceptUnicodeNForTextStartingWithSpacePrefix()
        {
            var select = parser.Parse("SELECT bla + N' lala' AS Bla FROM xxxxx");
            select.Should(Have.Length(1));
            select[0].Should(Be.EqualTo("bla + N' lala'"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldRemoveAliases()
        {
            var select = parser.Parse("SELECT bla lala,ble AS lala,(bli) la,(ble,(bla) AS lolo) [lala] FROM xxxxx");
            select.Should(Have.Length(4));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("(bli)"));
            select[3].Should(Be.EqualTo("(ble,(bla) AS lolo)"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotTakeOperationAsAliases()
        {
            var select = parser.Parse("SELECT bla + ble, bla - ble FROM xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla + ble"));
            select[1].Should(Be.EqualTo("bla - ble"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotRemoveAsWordInsideParenthesis()
        {
            var select = parser.Parse("SELECT bla,(ble AS lala),bli FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("(ble AS lala)"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldSupportSeveralSpaces()
        {
            var select = parser.Parse(" SELECT   bla  +    bla,  (ble   AS lala)   , bli   la   FROM    xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla  +    bla"));
            select[1].Should(Be.EqualTo("(ble   AS lala)"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }


        [Test]
        public void ShouldNotSplitACommaUsedInsideParenthesis()
        {
            var select = parser.Parse("SELECT bla,(ble,bli),blo FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("(ble,bli)"));
            select[2].Should(Be.EqualTo("blo"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotSplitACommaUsedInsideSquareParenthesis()
        {
            var select = parser.Parse("SELECT bla,[ble,bli] FROM xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("[ble,bli]"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldSupportDeepParenthesisUsage()
        {
            var select = parser.Parse("SELECT bla,((ble,bli),blo),blu FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("((ble,bli),blo)"));
            select[2].Should(Be.EqualTo("blu"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotSplitACommaUsedInsideQuotationMarks()
        {
            var select = parser.Parse("SELECT bla,\"ble,bli\" FROM xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("\"ble,bli\""));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldGetCountFunction()
        {
            var select = parser.Parse("SELECT COUNT(*) AS bla FROM xxxxx");
            select.Should(Have.Length(1));
            select[0].Should(Be.EqualTo("COUNT(*)"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldGetStringWithSpaces()
        {
            var select = parser.Parse("SELECT ' n n n ' FROM xxxxx");
            select.Should(Have.Length(1));
            select[0].Should(Be.EqualTo("' n n n '"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }
    }
}